package com.redissdk.redis;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.redissdk.redis.common.ms.MasterSlaveJedis;
import com.redissdk.redis.common.ms.MasterSlaveJedisPool;

import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.util.Pool;

/**
 * 项目名称:[redisx] 
 * 包:[com.redissdk.redis] 
 * 文件名称:[RedisMasterSlaveUtil] 
 * 描述:[Redis
 * 工具类-RedisMasterSlave] 
 * 创建人:[陆文斌] 
 * 创建时间:[2016年12月5日 下午5:37:53] 
 * 修改人:[陆文斌]
 * 修改时间:[2016年12月5日 下午5:37:53] 
 * 修改备注:[说明本次修改内容] 
 * 版权所有:luwenbin006@163.com
 * 版本:[v1.0]
 */
public class RedisMasterSlaveUtil
{

    protected static Logger logger = Logger.getLogger(RedisMasterSlaveUtil.class);

    // redis_master 服务器
    private static HostAndPort master_server;

    // redis_salve 服务器
    private static HostAndPort slave_server;

    // 访问密码
    private static String AUTH = null;

    // 可用连接实例的最大数目，默认值为8；
    // 如果赋值为-1，则表示不限制；如果pool已经分配了maxActive个jedis实例，则此时pool的状态为exhausted(耗尽)。
    private static int MAX_ACTIVE = 0;

    // 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例，默认值也是8。
    private static int MAX_IDLE = 0;

    // 等待可用连接的最大时间，单位毫秒，默认值为-1，表示永不超时。如果超过等待时间，则直接抛出JedisConnectionException；
    private static int MAX_WAIT = 0;

    // 超时时间
    private static int TIMEOUT = 0;

    // 在borrow一个jedis实例时，是否提前进行validate操作；如果为true，则得到的jedis实例均是可用的；
    private static boolean TEST_ON_BORROW = false;

    private static Pool<MasterSlaveJedis> masterSlaveJedisPool = null;

    /**
     * redis过期时间,以秒为单位
     */
    public final static int EXRP_HOUR = 60 * 60; // 一小时
    public final static int EXRP_DAY = 60 * 60 * 24; // 一天
    public final static int EXRP_MONTH = 60 * 60 * 24 * 30; // 一个月

    /**
     * 初始化Redis连接池
     */
    private static void initialPool()
    {

        initRedisConfigValue();
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(MAX_ACTIVE);
        config.setMaxIdle(MAX_IDLE);
        config.setMaxWaitMillis(MAX_WAIT);
        config.setTestOnBorrow(TEST_ON_BORROW);

        // sentinels.add("127.0.0.1:63792");
        masterSlaveJedisPool = new MasterSlaveJedisPool(master_server, slave_server, config,TIMEOUT, AUTH);
        // MasterSlaveJedis masterSlaveJedis =
        // masterSlaveJedisPool.getResource();
        // masterSlaveJedis.auth(AUTH);
        // //>>> masterSlaveJedis = MasterSlaveJedis
        // {master=192.168.137.101:6379, slaves=[192.168.137.101:6380,
        // 192.168.137.101:6381]}
        // System.out.println(">>> masterSlaveJedis = " + masterSlaveJedis);
        //
        // masterSlaveJedis.set("nowTime", "2015-03-16 15:34:55"); // The
        // underlying actually call the master.set("nowTime", "2015-03-16
        // 15:34:55");
        //
        // LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(200));
        //
        // String slaveHolder1 = "myslave1";
        // Jedis slave1 = masterSlaveJedis.opsForSlave(slaveHolder1); // if no
        // any slave found, opsForSlave() will return master as a slave to be
        // use
        // System.out.println(">>> nowTime = " + slave1.get("nowTime")); //>>>
        // nowTime = 2015-03-16 15:34:55
        //
        // String slaveHolder2 = "myslave1";
        // Jedis slave2 = masterSlaveJedis.opsForSlave(slaveHolder2);
        // System.out.println(">>> nowTime = " + slave2.get("nowTime")); //>>>
        // nowTime = 2015-03-16 15:34:55
        //
        // System.out.println(slave1.equals(slave2)); // must be true if
        // slaveHolder1 equals slaveHolder2
        //
        // masterSlaveJedisPool.returnResource(masterSlaveJedis);

    }

    private static void initRedisConfigValue()
    {
        // TODO Auto-generated method stub
        // master_server=192.168.1.16
        // master_port=6380
        master_server = new HostAndPort(
                FileUtil.getPropertyValue("properties/redis_master_salve.properties", "master_server"),
                FileUtil.getPropertyValueInt("properties/redis_master_salve.properties", "master_port"));

        // salve_server=192.168.1.16
        // salve_port=6380
        slave_server = new HostAndPort(
                FileUtil.getPropertyValue("properties/redis_master_salve.properties", "salve_server"),
                FileUtil.getPropertyValueInt("properties/redis_master_salve.properties", "salve_port"));

        AUTH = FileUtil.getPropertyValue("properties/redis_master_salve.properties", "auth");
        MAX_ACTIVE = FileUtil.getPropertyValueInt("properties/redis_master_salve.properties", "max_active");

        MAX_IDLE = FileUtil.getPropertyValueInt("properties/redis_master_salve.properties", "max_idle");

        MAX_WAIT = FileUtil.getPropertyValueInt("properties/redis_master_salve.properties", "max_wait");

        TIMEOUT = FileUtil.getPropertyValueInt("properties/redis_master_salve.properties", "timeout");

        TEST_ON_BORROW = FileUtil.getPropertyValueBoolean("properties/redis_master_salve.properties", "test_on_borrow");

        FileUtil.remove("properties/redis_sentinel.properties");
    }

    /**
     * 在多线程环境同步初始化
     */
    private static synchronized void poolInit()
    {
        if (masterSlaveJedisPool == null)
        {
            initialPool();
        }
    }

    /**
     * 同步获取Jedis实例
     * 
     * @return Jedis
     */
    public synchronized static MasterSlaveJedis getJedis()
    {
        if (masterSlaveJedisPool == null)
        {
            poolInit();
        }
        MasterSlaveJedis jedis = null;
        try
        {
            if (masterSlaveJedisPool != null)
            {
                jedis = masterSlaveJedisPool.getResource();
            }
        }
        catch (Exception e)
        {
            returnResource(jedis);
            logger.error("Get jedis error : " + e);
        }

        return jedis;
    }

    // /**
    // * slave jedis
    // * @return
    // */
    // public synchronized static Jedis getSlaveJedis()
    // {
    // if (masterSlaveJedisPool == null)
    // {
    // poolInit();
    // }
    // MasterSlaveJedis masterSlaveJedis = null;
    // Jedis jedis = null;
    // try
    // {
    // if (masterSlaveJedisPool != null)
    // {
    // masterSlaveJedis = masterSlaveJedisPool.getResource();
    // jedis = masterSlaveJedis.opsForSlave();
    // }
    // }
    // catch (Exception e)
    // {
    // logger.error("Get jedis error : " + e);
    // }
    //
    // return jedis;
    // }

    /**
     * 释放jedis资源
     * 
     * @param jedis
     */
    public static void returnResource(final MasterSlaveJedis jedis)
    {
        if (jedis != null)
        {
            jedis.close();
        }
    }

    /**
     * 设置 String
     * 
     * @param key
     * @param value
     */
    public static String setString(String key, String value)
    {
        MasterSlaveJedis masterSlaveJedis = null;
        String r_str = "nil";
        try
        {
            value = StringUtils.isEmpty(value) ? "" : value;
            masterSlaveJedis = getJedis();
            r_str = masterSlaveJedis.set(key, value);
        }
        catch (Exception e)
        {
            // return jedis object to pll and set jedis is null.
            returnResource(masterSlaveJedis);
            masterSlaveJedis = null;
            logger.error("Set key error : " + e);
        }
        finally
        {
            returnResource(masterSlaveJedis);
        }
        return r_str;
    }

    /**
     * 设置 过期时间
     * 
     * @param key
     * @param seconds
     *            以秒为单位
     * @param value
     */
    public static String setString(String key, String value, int expirationTime)
    {
        MasterSlaveJedis masterSlaveJedis = null;
        String r_str = "nil";
        try
        {
            value = StringUtils.isEmpty(value) ? "" : value;
            masterSlaveJedis = getJedis();
            r_str = masterSlaveJedis.setex(key, expirationTime, value);
        }
        catch (Exception e)
        {
            // return jedis object to pll and set jedis is null.
            returnResource(masterSlaveJedis);
            masterSlaveJedis = null;
            logger.error("Set keyex error : " + e);
        }
        finally
        {
            returnResource(masterSlaveJedis);
        }

        return r_str;
    }

    public static Set<byte[]> getKeys(byte[] keys)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        Set<byte[]> set_ = masterSlaveJedis.opsForSlave().keys(keys);
        returnResource(masterSlaveJedis);
        return set_;

    }

    public static Set<String> getKeys(String keys)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        Set<String> set_ = masterSlaveJedis.opsForSlave().keys(keys);
        returnResource(masterSlaveJedis);
        return set_;

    }

    public static Set<byte[]> hkeys(byte[] hkeys)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        Set<byte[]> set_ = masterSlaveJedis.opsForSlave().hkeys(hkeys);
        returnResource(masterSlaveJedis);
        return set_;
    }

    public static Set<String> hkeys(String hkeys)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        Set<String> set_ = masterSlaveJedis.opsForSlave().hkeys(hkeys);
        returnResource(masterSlaveJedis);
        return set_;
    }

    public static Collection<byte[]> hvals(byte[] hvals)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        Collection<byte[]> collection = masterSlaveJedis.opsForSlave().hvals(hvals);
        returnResource(masterSlaveJedis);
        return collection;
    }

    public static List<String> hvals(String hvals)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        List<String> list = masterSlaveJedis.opsForSlave().hvals(hvals);
        returnResource(masterSlaveJedis);
        return list;
    }

    /**
     * 获取String值
     * 
     * @param key
     * @return value
     */
    public static String getString(String key)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        String r_str = null;
        if (masterSlaveJedis == null || !masterSlaveJedis.exists(key))
        {
            r_str = null;
            returnResource(masterSlaveJedis);
        }
        else
        {
            r_str = masterSlaveJedis.opsForSlave().get(key);
            returnResource(masterSlaveJedis);
        }

        return r_str;
    }

    public static String setObject(String key, Object obj, int expirationTime)
    {
        String r_t = null;
        MasterSlaveJedis masterSlaveJedis = getJedis();
        try
        {

            r_t = masterSlaveJedis.setex(key.getBytes(), expirationTime,
                    SerializationAndCompressUtils.fastSerialize(obj));

        }
        catch (Exception e)
        {
            // return jedis object to pll and set jedis is null.
            returnResource(masterSlaveJedis);
            masterSlaveJedis = null;
            e.printStackTrace();
        }
        finally
        {
            returnResource(masterSlaveJedis);
        }
        return r_t;

    }

    public static String setObject(String key, Object obj)
    {
        String r_t = null;
        MasterSlaveJedis masterSlaveJedis = getJedis();
        try
        {
            r_t = masterSlaveJedis.set(key.getBytes(), SerializationAndCompressUtils.fastSerialize(obj));

        }
        catch (Exception e)
        {
            // return jedis object to pll and set jedis is null.
            returnResource(masterSlaveJedis);
            masterSlaveJedis = null;
            e.printStackTrace();
        }
        finally
        {
            returnResource(masterSlaveJedis);

        }
        return r_t;

    }

    public static Long del(String key)
    {
        long d_l = 0l;
        MasterSlaveJedis masterSlaveJedis = getJedis();
        try
        {

            d_l = masterSlaveJedis.del(key);

        }
        catch (Exception e)
        {
            // return jedis object to pll and set jedis is null.
            returnResource(masterSlaveJedis);
            masterSlaveJedis = null;
            e.printStackTrace();
        }
        finally
        {

            returnResource(masterSlaveJedis);

        }
        return d_l;

    }

    public static Long del(byte[] key)
    {
        Long d_l = 0l;
        MasterSlaveJedis masterSlaveJedis = getJedis();
        try
        {

            d_l = masterSlaveJedis.del(key);

        }
        catch (Exception e)
        {

            // return jedis object to pll and set jedis is null.
            returnResource(masterSlaveJedis);
            masterSlaveJedis = null;
            e.printStackTrace();
        }
        finally
        {

            returnResource(masterSlaveJedis);

        }
        return d_l;

    }

    public static Long del(byte[]... key)
    {
        Long d_l = 0l;
        MasterSlaveJedis masterSlaveJedis = getJedis();
        try
        {
            d_l = masterSlaveJedis.del(key);
        }
        catch (Exception e)
        {
            // return jedis object to pll and set jedis is null.
            returnResource(masterSlaveJedis);
            masterSlaveJedis = null;
            e.printStackTrace();
        }
        finally
        {

            returnResource(masterSlaveJedis);

        }
        return d_l;

    }

    /**
     * 获取Object
     * 
     * @param key
     * @return
     * @return value
     */
    public static <T> T getObject(String key, Class<T> classz)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        T t = null;
        if (masterSlaveJedis == null || !masterSlaveJedis.exists(key))
        {
            t = null;
            returnResource(masterSlaveJedis);
        }
        else
        {
            byte[] value = masterSlaveJedis.get(key.getBytes());

            try
            {

                t = classz.cast(SerializationAndCompressUtils.fastDeserialize(value));

            }
            catch (Exception e)
            {
                // return jedis object to pll and set jedis is null.
                returnResource(masterSlaveJedis);
                masterSlaveJedis = null;

                e.printStackTrace();
            }
            finally
            {
                returnResource(masterSlaveJedis);
            }
        }
        return t;
    }

    public static Long hdel(String key, String field)
    {
        Long r_l = 0l;
        MasterSlaveJedis masterSlaveJedis = getJedis();
        if (masterSlaveJedis == null)
        {
            r_l = 0l;
        }
        else
        {
            try
            {

                r_l = masterSlaveJedis.hdel(key, field);
            }
            catch (Exception e)
            {
                // return jedis object to pll and set jedis is null.
                returnResource(masterSlaveJedis);
                masterSlaveJedis = null;

                e.printStackTrace();
            }
            finally
            {

                returnResource(masterSlaveJedis);

            }
        }

        return r_l;
    }

    public static Map<String, String> hgetall(String key)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        Map<String, String> map = null;
        if (masterSlaveJedis == null)
        {
            map = null;

        }
        else
        {
            try
            {
                map = masterSlaveJedis.hgetAll(key);

            }
            catch (Exception e)
            {

                // return jedis object to pll and set jedis is null.
                returnResource(masterSlaveJedis);
                masterSlaveJedis = null;
                e.printStackTrace();
            }
            finally
            {

                returnResource(masterSlaveJedis);

            }
        }

        return map;
    }

    public static Long hincrBy(String key, String field, long value)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        Long r_l = 0l;
        if (masterSlaveJedis == null)
        {
            r_l = 0l;
        }
        else
        {
            try
            {
                r_l = masterSlaveJedis.hincrBy(key, field, value);
            }
            catch (Exception e)
            {
                // return jedis object to pll and set jedis is null.
                returnResource(masterSlaveJedis);
                masterSlaveJedis = null;
                e.printStackTrace();
            }
            finally
            {
                if (null != masterSlaveJedis)
                {
                    returnResource(masterSlaveJedis);
                }
            }
        }

        return r_l;
    }
}